<?php

/**
 * ResMania
 * More Information contact: info@resmania.com
 *
 * @package ResMania Model Class
 * @version 1.2.6
 * @author webformatique
 * @copyright (C) 2010- webformatique
 * @license GNU/GPLv3 http://www.gnu.org/copyleft/gpl.html
 */

// no direct access
defined('_JEXEC') or die('Restricted access');

class ResMania_Install_Model {

    private $_installerVersion = "1.3.0";
    private $_disto_point = "http://resmania.googlecode.com/files/core.zip";
    private $_zendFrameworkMinVersion = "1.9.5";

    /**
     * Get the installer version
     */
    function getVersion() {
        return $this->_installerVersion;
    }


    /**
     * Get the distribution point
     */
    function getDistroPoint() {
        return $this->_disto_point;
    }


    /**
     * create SID for ajax tracking
     */
    function getSID() {
        // generate an ID to use to use for the session
        return uniqid();
    }

    /*
     * This will check the folder status
     *
     * Return   int     0 = not available, not creatable / 1 = already exists
     *                  2 = OK
     */

    function checkfolder($JoomlaBase) {

        $ResManiaFolder = $JoomlaBase . DS . 'RM';

        // for existing RM folder
        if (file_exists($ResManiaFolder)) {
            if (file_exists($ResManiaFolder . DS . "system" . DS . "application" . DS . "classes" . DS . "RM" . DS . "Connector.php")) {
                if (is_writable($ResManiaFolder)) {
                    return 1;
                } else {
                    return 0;
                }
            } else {

                // add a test file
                copy($JoomlaBase.DS."administrator".DS."components".DS."com_resmania".DS."installation".DS."test".DS."sizecheck.txt",$ResManiaFolder.DS."sizecheck.txt");

                if (is_writable($ResManiaFolder)) {
                    return 2;
                } else {
                    return 0;
                }
            }
        } else {
            // for new RM folder

            if (mkdir($ResManiaFolder, 0775)){
                // add a test file
                copy($JoomlaBase.DS."administrator".DS."components".DS."com_resmania".DS."installation".DS."test".DS."sizecheck.txt",$ResManiaFolder.DS."sizecheck.txt");
                return 2;
            } else {
                return 0;
            }
        }
    }

    /**
     * Checks if we can get the destination file size used for the download progress.
     *
     * @param string $RMSiteBase
     * @param string $JoomlaBase
     * @return boolean
     */
    function checkDestinationSize($RMSiteBase,$JoomlaBase) {

        $URLCheckFile = $RMSiteBase.'RM/sizecheck.txt';
        $PathCheckFile = $JoomlaBase . DS . 'RM' . DS . "sizecheck.txt";

        if ($this->getRemoteFileSize($URLCheckFile)>0){
            //$this->deleteFile($PathCheckFile);
            return 1;
        }
         //$this->deleteFile($PathCheckFile);
        return 0;

    }

    /**
     *  checks if a core.zip file is already present, used for resume.
     *
     * @param string $RMSiteBase
     * @return boolean
     */
    function checkCoreFileAlreadyExists($RMSiteBase){

        $URLCoreFile = $RMSiteBase.'RM/core.zip';

        if ($this->getRemoteFileSize($URLCoreFile)>0){
            return 1;
        }
        return 0;
    }
    /*
     * This will return the DB support
     *
     * return   boolean     true = ok
     */

    function checkdb() {
        $db = & JFactory::getDBO();
        $sql = 'CREATE TABLE  `RM_db_check` (
                `test` TINYINT( 1 ) NOT NULL
                ) ENGINE = INNODB;';
        $db->setQuery($sql);

        try {
            $db->query();
            $innoDB = true;
        } catch (Exception $e) {
            $innoDB = false;
        }

        $db->setQuery("DROP TABLE `RM_db_check`");
        $db->query();

        return $innoDB;
    }

    /**
     * Check zlib support
     */
    function checkZlib() {
        if (!extension_loaded('zlib')) {
            $zlibSupport = false;
        } else {
            $zlibSupport = true;
        }

        return $zlibSupport;
    }

    /**
     * Check PDO support
     */
    function checkPDO() {
        if (!extension_loaded('pdo_mysql')) {
            $pdoSupport = false;
        } else {
            $pdoSupport = true;
        }

        return $pdoSupport;
    }

    function checkMySQLi() {
        if (function_exists('mysqli_connect')) {
            $MySQLi = true;
        } else {
            $MySQLi = false;
        }

        return $MySQLi;
    }

    /*
     * This will look for the existance of any existing ResMania tables
     *
     * return boolean   true = found
     */

    function getDBVersion() {
        $db = & JFactory::getDBO();
        $sql = 'SELECT  `db_version`
                FROM  `rm_system`
                LIMIT 1';
        try {
            $db->setQuery($sql);
            $result = $db->loadObject();
            if (!empty($result)) {
                $dbversion = $result->db_version;
            } else {
                $dbversion = 0;
            }
        } catch (Exception $e) {
            $dbversion = 0;
        }

        return $dbversion;
    }

    /**
     * @return array() - array(<status code>, <zf version>)
     * status code:
     * 0 - resmania couldn't be installed
     * 1 - resmania could be installed
     * zf version:
     * 0 - if ZF is not installed
     * <string> - if ZF installed
     */
    function checkzendframework() {
        @include_once('Zend/Version.php');
        if (class_exists('Zend_Version') == false) {
            return array(1, 0);
        }
        if (Zend_Version::compareVersion($this->_zendFrameworkMinVersion) >= 0) {
            return array(0, Zend_Version::VERSION);
        } else {
            return array(1, Zend_Version::VERSION);
        }
    }

    /*
     * Check if Zend Optimizer is installed
     *
     * return  Boolean     true = installed
     */

    function checkzend() {
        $newZendCheck = $this->_checkZendOptimizer();
        if ($newZendCheck == true) {
            return true;
        }

        $zend = false;
        $phpInfoValue = $this->getPHPInfoValue("Zend Optimizer");
        if (!empty($phpInfoValue)) {
            $value = trim($phpInfoValue, "+vV ");
            $valueArray = explode(".", $value);
            $major = (int) $valueArray[0];
            $minor = (int) $valueArray[1];
            $sub = (int) $valueArray[2];

            if ($major >= 3) {
                if ($major == 4) {
                    $zend = true;
                } else if ($minor >= 3 && $sub >= 3) {
                    $zend = true;
                }
            }

            if ($zend) {
                $this->log('Zend Optimizer Found, Version: ' . $major . '.' . $minor . '.' . $sub);
            } // check our value of $zend and exploded values
        }
        return $zend;
    }

    /**
     * Return a PHP Value based on the specified token
     *
     * @params  string  $strToken   The token to search for
     * @return  string
     */
    function getPHPInfoValue($strToken) {
        ob_start();
        phpinfo(1);
        $output = ob_get_contents();
        ob_end_clean();

        $output = str_replace(array("&gt;", "&lt;", "&quot;", "&amp;", "'", "&nbsp;"), array(">", "<", "\"", "&", "'", " "), $output);

        if (strstr($output, $strToken)) {
            $value = split($strToken, $output);
            $value = split(",", $value[1]);
            $value = trim($value[0]);
            return $value;
        } else {
            return false;
        }
    }

    /*
     * Check the php version
     */

    function checkphp($v) {
        if (function_exists('version_compare') == false) {
            return false;
        }
        $phpcheck = version_compare(PHP_VERSION, $v, '>=');
        if ($phpcheck == true) {
            $phpversion = "Ok";
        } else {
            $phpversion = "Failed";
        }
        $this->log("PHP Version: " . $phpversion);
        return $phpcheck;
    }

    /*
     * this is used to check anything that could be a problem
     */

    function checkPHPdirectivesOptional() {

        // first of all see if we can add an override (this depends on safe mode)
        // but it is worth a try... (600 = 10 mins)
        ini_set('max_execution_time', 600);
        ini_set('max_input_time', 600);

        // now check the values...
        $failed = 0;
        if ((int) ini_get('max_execution_time') < 240)
            $failed+=1;
        if ((int) ini_get('max_input_time') < 240)
            $failed+=1;

        if ($failed > 0) {
            return false;
        } else {
            return true;
        }
    }
    function checkPHPdirectivesRequired() {

        // first of all see if we can add an override (this depends on safe mode)
        // but it is worth a try... (600 = 10 mins)
        ini_set('max_execution_time', 600);
        ini_set('max_input_time', 600);

        // now check the values...
       if ((int) trim(ini_get('memory_limit'), "Mm") < 32)
            $failed+=1;
        if ((int) trim(ini_get('allow_url_fopen')) == 0)
            $failed+=1;

        if ($failed > 0) {
            return false;
        } else {
            return true;
        }
    }

    /*
     * Remove non-base extensions
     */

    function removeNonBaseExtensions($baseDir) {

        $this->log("Non Base Modules Un-install Process Started");
        $resultModules = true;
        $resultPlugins = true;


        // modules
        $baseModules = array('Categories', 'DailyPrices', 'EmailNotifications', 'Extras', 'FormDesigner', 'HourlyPrices', 'Locations', 'Payments', 'SEF', 'UnitTypeManager');
        $allModules = $this->getAllExtensions('rm_modules');
        if (!empty($allModules)) {
            foreach ($allModules as $module) {
                $moduleName = $module->name;
                if (!in_array($moduleName, $baseModules)) {
                    // if the module is not in base modules then un-install it...
                    $sqlfile = $baseDir . DS . 'modules' . DS . $moduleName . DS . 'sql' . DS . 'uninstall.sql';
                    if (file_exists($sqlfile)) {
                        $filecontents = file_get_contents($sqlfile);
                        $resultModules = $this->parseSQL($filecontents, false);
                        if ($resultModules) {

                            $this->log("Modules removed from DB successfull");

                            // if the db passes then remove the module extension...
                            $delResultModules = true;
                            $delResultModules = $this->deleteFolder($baseDir . DS . 'modules' . DS . $moduleName);
                            $delResultModules = $this->deleteFolder($baseDir . DS . 'userdata' . DS . 'modules' . DS . $moduleName);
                            if (!$delResultModules)
                                $resultModules = false;
                        }
                    }
                }
            }
        }

        if (!$resultModules
            )$this->log("Non base module un-install failed");

        // plugins
        $basePlugins = array('GMaps', 'PayPal', 'Paylater', 'Taxes');
        $allPlugins = $this->getAllExtensions('rm_plugins');
        if (!empty($allPlugins)) {
            foreach ($allPlugins as $plugin) {
                $pluginName = $plugin->name;
                if (!in_array($pluginName, $basePlugins)) {
                    // if the plugin is not in base modules then un-install it...
                    $sqlfile = $baseDir . DS . 'plugins' . DS . $pluginName . DS . 'sql' . DS . 'uninstall.sql';
                    if (file_exists($sqlfile)) {
                        $filecontents = file_get_contents($sqlfile);
                        $resultPlugins = $this->parseSQL($filecontents, false);
                        if ($resultPlugins) {

                            $this->log("Plugins removed from DB successfull");

                            // if the db passes then remove the module extension...
                            $delResultPlugins = true;
                            $delResultPlugins = $this->deleteFolder($baseDir . DS . 'plugins' . DS . $pluginName);
                            $delResultPlugins = $this->deleteFolder($baseDir . DS . 'userdata' . DS . 'plugins' . DS . $pluginName);
                            if (!$delResultPlugins)
                                $resultPlugins = false;
                        }
                    }
                }
            }
        }
        if (!$resultPlugins
            )$this->log("Non base plugins un-install failed");

        if (!$resultPlugins || !$resultModules) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Delete a file.
     *
     * @param string $file full file path
     * @return bool
     */
    private function deleteFile($file) {
        return @unlink($file);
    }

    /**
     * Delete files passed in an array
     *
     * @param array $files  an array of files that need to be deleted
     * @return boolean - true if success
     */
    private function deleteFiles($files) {

        $result = true;
        if (!is_array($files))
            return false;

        foreach ($files as $file) {
            $result = $this->deleteFile($file);
        }
        return $result; // if delete of any of the files fails return false
    }

    /**
     * Delete recursivly folder/file in the system
     *
     * @param string $foldername - full folder/file path
     * @return bool
     */
    private function deleteFolder($foldername) {
        if (is_file($foldername)) {
            return $this->deleteFile($foldername);
        }
        if (is_dir($foldername)) {
            if ($handle = opendir($foldername)) {
                while (false !== ($file = readdir($handle))) {
                    if ($file != "." && $file != "..") {
                        $this->deleteFolder($foldername . DIRECTORY_SEPARATOR . $file);
                    }
                }
            }
            closedir($handle);
            rmdir($foldername);
        }
        return true;
    }

    function getAllExtensions($table) {
        $db = & JFactory::getDBO();
        $sql = 'SELECT  `name`
                FROM  `' . $table . '`';
        $db->setQuery($sql);
        return $db->loadObjectList();
    }

    /**
     * Parses and executes the SQL line by line
     *
     * @return bool true for success, false for failed
     */
    function parseSQL($sqlscript, $isUpGrade = false, $queriesCount = null) {
        $queries = $this->splitSQL($sqlscript);
        $queriesNumber = count($queries);

        if ($isUpGrade == true) {
            if ($queriesCount !== null && $queriesNumber != $queriesCount) {
                $this->log("SQL Query: Wrong number of queries - " . $queriesNumber . ". Should be " . $queriesCount);
                return false;
            }
        }

        //we need to check how many hours
        if (count($queries) !== 0) {

            $db = & JFactory::getDBO();

            foreach ($queries as $query) {
                $db->setQuery($query);
                $db->query();
                $error = $db->getErrorMsg();

                if (!$error) {
                    $errMsg = "Ok";
                } else {
                    $errMsg = $error;
                }
                $this->log("SQL Query: " . $query . "    -> status: " . $errMsg);

                if ($error) {
                    return false;
                }
            }
        }
        if ($_SESSION['licenseKey']!==""){
            $db->setQuery("UPDATE  `rm_config` SET  `value` = '".$_SESSION['licenseKey']."' WHERE  `rm_config`.`id` =  'rm_config_licensekey'");
            $db->query();
        }
        return true;
    }

    /**
     * @param string
     * @return array
     */
    function splitSQL($sql) {
        $sql = trim($sql);

        //Remove comments
        $sql = preg_replace("/\n\#[^\n]*/", '', $sql);
        $sql = preg_replace("/^--[^\n]*/", '', $sql); //First comment
        $sql = preg_replace("/\n--[^\n]*/", '', $sql);

        //Remove 'tabs'
        $sql = preg_replace("/\t/", '', $sql);

        $buffer = array();
        $ret = array();
        $in_string = false;

        for ($i = 0; $i < strlen($sql) - 1; $i++) {
            if ($sql[$i] == ";" && !$in_string) {
                $ret[] = trim(substr($sql, 0, $i));
                $sql = substr($sql, $i + 1);
                $i = 0;
            }

            if ($in_string && ($sql[$i] == $in_string) && $buffer[1] != "\\" && ($sql[$i] != "'" || $sql[$i - 1] != "'" || $sql[$i - 2] != "\\")) {
                $in_string = false;
            } elseif (
                    !$in_string
                    && ($sql[$i] == '"' || $sql[$i] == "'")
                    && (!isset($buffer[0]) || $buffer[0] != "\\")
            ) {
                $in_string = $sql[$i];
            }

            if (isset($buffer[1])) {
                $buffer[0] = $buffer[1];
            }
            $buffer[1] = $sql[$i];
        }

        if (!empty($sql)) {
            $ret[] = trim($sql);
        }
        return ($ret);
    }

    /*
     * Gets the Source File Size
     */

    function getSourceSize($sid) {

        @session_start($sid); // start or resume a session
        if (isset($_SESSION['sourceFileSize'])) {
            return $_SESSION['sourceFileSize'];
        } else {
            return 0;
        }
    }

    /*
     * stores the Source FileSize
     */

    function setSourceSize($sourceSize) {

        if ($sourceSize == 0) {
            return false;
        }

        if (isset($_SESSION['sourceFileSize'])) {
            unset($_SESSION['sourceFileSize']);
        } //clear it, if it's found

        $_SESSION['sourceFileSize'] = $sourceSize; // set the new value

        session_write_close();

        $this->log("Source File Size: " . $sourceSize); // log it
        $this->log("Session Saved Source File Size: " . $_SESSION['sourceFileSize']); // log it

        return true;
    }

    /*
     * Write to installation Log
     */

    function log($message) {
        $logfile = dirname(__FILE__) . DS . ".." . DS . "install.log";
        $fh = @fopen($logfile, 'a+');
        if (!$fh)
            return false;
        fwrite($fh, date("Y-m-d h:i:s") . ": " . $message . "\n");
        fclose($fh);
        return true;
    }

    /*
     *  Get filesize of local files.
     */
    function getRemoteFileSize($url) {
        $parsed = parse_url($url);
        $host = $parsed["host"];
        $fp = @fsockopen($host, 80, $errno, $errstr, 20);
        if (!$fp) {
            return false;
        } else {
            @fputs($fp, "HEAD $url HTTP/1.1\r\n");
            @fputs($fp, "HOST: $host\r\n");
            @fputs($fp, "Connection: close\r\n\r\n");
            $headers = "";
            while (!@feof($fp)
                )$headers .= @ fgets($fp, 128);
        }
        @fclose($fp);
        $return = false;
        $arr_headers = explode("\n", $headers);
        foreach ($arr_headers as $header) {
            // follow redirect
            $s = 'Location: ';
            if (substr(strtolower($header), 0, strlen($s)) == strtolower($s)) {
                $url = trim(substr($header, strlen($s)));
                return $this->getRemoteFileSize($url);
            }

            // parse for content length
            $s = "Content-Length: ";
            if (substr(strtolower($header), 0, strlen($s)) == strtolower($s)) {
                $return = trim(substr($header, strlen($s)));
                break;
            }
        }
        $this->log($return);
        return $return;
    }


    /**
     * Get the remote download URL
     */
    function getDownloadSource(){
        return $this->_disto_point;
    }

    /*
     * Unzip file
     */
    function unpackZip($source, $destination) {

        require_once dirname(__FILE__) . DS . ".." . DS . "libs" . DS . "php" . DS . "pclzip.lib.php";

        $zip = new PclZip($source);

        if ($zip->extract(PCLZIP_OPT_PATH, $destination) == 0) {
            $this->log("File Extraction Failed: errorcode: " . $zip->errorInfo(true));
            return false;
        }

        $this->log("File Extraction Complete Ok");
        return true;
    }

    /*
     * Substitute for PHP Copy
     */

    function fileDownload($file_source, $file_target) {

        $ch = curl_init($file_source);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $data = curl_exec($ch);

        curl_close($ch);

        file_put_contents($file_target, $data);

        return true;

    }
    
}
?>
